#include "StdAfx.h"
#include "resource.h"
#include "AboutDlg.h"
#include "MainDlg.h"

#include "string"

using namespace std;

template <typename T>
inline T *AllocArray(size_t n)
{
    return (T*)calloc(n, sizeof(T));
}

/* Caller needs to free() the result */
char *ToMultiByte(const WCHAR *txt, UINT codePage, int cchTxtLen)
{
    if (!txt) return NULL;

    int requiredBufSize = WideCharToMultiByte(codePage, 0, txt, cchTxtLen, NULL, 0, NULL, NULL);
    if (0 == requiredBufSize)
        return NULL;
    char *res = AllocArray<char>(requiredBufSize+1);
    if (!res)
        return NULL;
    WideCharToMultiByte(codePage, 0, txt, cchTxtLen, res, requiredBufSize, NULL, NULL);
    return res;
}

/* Caller needs to free() the result */
WCHAR *ToWideChar(const char *src, UINT codePage, int cbSrcLen)
{
    if (!src) return NULL;

    int requiredBufSize = MultiByteToWideChar(codePage, 0, src, cbSrcLen, NULL, 0);
    if (0 == requiredBufSize)
        return NULL;
    WCHAR *res = AllocArray<WCHAR>(requiredBufSize+1);
    if (!res)
        return NULL;
    MultiByteToWideChar(codePage, 0, src, cbSrcLen, res, requiredBufSize);
    return res;
}

inline char *   ToUtf8(const WCHAR *src)  { return ToMultiByte(src, CP_UTF8, -1); }
inline WCHAR *  FromUtf8(const char *src) { return ToWideChar(src, CP_UTF8, -1); }


inline BOOL IsDigit(WCHAR ch)
{
    if ('0' <= ch && ch <= '9')
        return TRUE; 

    return FALSE;
}

BOOL IsOctal(WCHAR* pOct)
{
    if ('\\' == *pOct && IsDigit(*(pOct + 1)))
        return TRUE; 

    return FALSE;
}

LRESULT CMainDlg::OnBnClickedTxt2Oct(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
    WCHAR wszText[1024] = { 0 };
    CHAR* szUTF8Text = NULL;
    BYTE* pChar = NULL;
    wstring wstrOct;
    BOOL bKeepAscii = FALSE;

    GetDlgItemText(IDC_EDIT_TXT, wszText, _countof(wszText));
    bKeepAscii = IsDlgButtonChecked(IDC_CHECK_KEEP_ASCII);

    szUTF8Text = ToUtf8(wszText);

    pChar = (BYTE*)szUTF8Text;
    while (*pChar)
    {
        WCHAR wszOct[5] = { 0 };

        if (*pChar < 128 && bKeepAscii)
        {
            WCHAR wChar[2] = { 0 };
            wChar[0] = *pChar++;
            wstrOct.append(wChar);
        } 
        else
        {
            swprintf_s(wszOct, _countof(wszOct), L"\\%o", *pChar++);
            wstrOct.append(wszOct);
        }
    }

    SetDlgItemText(IDC_EDIT_OCT, wstrOct.c_str());

    if (szUTF8Text)
        free(szUTF8Text);

    return 0;
}

LRESULT CMainDlg::OnBnClickedOct2Txt(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
    WCHAR wszOct[1024] = { 0 };
    CHAR  szUTF8Text[1024] = { 0 };

    WCHAR* pOct = wszOct;
    WCHAR* wszText = NULL;
    BOOL bKeepAscii = FALSE;

    int i = 0;

    SetDlgItemText(IDC_EDIT_TXT, L"");
    GetDlgItemText(IDC_EDIT_OCT, wszOct, _countof(wszOct));
    bKeepAscii = IsDlgButtonChecked(IDC_CHECK_KEEP_ASCII);

    while ('\0' != *pOct)
    {
        if (IsOctal(pOct)) 
        {
            int ch = 0;
            swscanf_s(++pOct, L"%o", &ch);
            szUTF8Text[i++] = ch;

            while (IsDigit(*pOct))
                pOct++;
        }
        else
        {
            if (bKeepAscii)
                szUTF8Text[i++] = (BYTE)*pOct++;
            else
                pOct++;
        }
    }

    wszText = FromUtf8(szUTF8Text);

    SetDlgItemText(IDC_EDIT_TXT, wszText);

    if (wszText)
        free(wszText);

    return 0;
}
